import sys
import math
from typing import List
from PySide6.QtWidgets import (QApplication, QMainWindow, QGraphicsView, QGraphicsScene, 
                              QGraphicsItem, QGraphicsPixmapItem, QGraphicsRectItem, 
                              QGraphicsPolygonItem, QGraphicsLineItem, QGraphicsEllipseItem,
                              QGraphicsItemGroup, QGraphicsTextItem, QDockWidget, 
                              QToolBar, QMenu, QFileDialog, QColorDialog, 
                              QSlider, QWidget, QVBoxLayout, QHBoxLayout, QLabel, 
                              QComboBox, QToolButton, QSpinBox, QDoubleSpinBox,
                              QSplitter, QMessageBox, QPushButton,QDialog,QWidgetAction,
                              QGraphicsSceneMouseEvent,QAbstractGraphicsShapeItem,QLineEdit
                              )
from PySide6.QtCore import Qt, QPointF, QPoint, QRectF,  QRect, QLineF, QSizeF, QUrl, QMimeData, Signal, QObject,QThread,QMarginsF
from PySide6.QtGui import (QPixmap, QImage, QImageReader,QPainter, QPen, QBrush, QColor, QPolygonF, QPolygon,
                          QTransform, QCursor, QFont, QIcon, QKeySequence, QDrag, QUndoStack, 
                          QUndoCommand, QAction,QActionGroup,QMouseEvent,QResizeEvent,QPainterPath
                          )
import cv2
import numpy as np
import datetime
import traceback
import requests
# from .graphics_items import *
# from .undo_command import *

class TransparentTextItem(QGraphicsTextItem):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setDefaultTextColor(Qt.white)
        self.padding = 4  # 文本边距
        self.setFont(QFont("Arial", 10))
    
    def paint(self, painter, option, widget=None):
        # 保存当前状态
        # painter.save()
        if not painter.isActive():
            painter.begin(self)
        
        # 绘制半透明黑色背景
        rect = self.boundingRect()
        bg_color = QColor(0, 0, 0, int(255 * 0.5))  # 50%透明黑色
        painter.fillRect(rect, bg_color)
        super().paint(painter, option, widget)
        # # 设置文本样式
        # painter.setPen(Qt.white)
        # painter.setFont(self.font())
        
        # # 绘制文本（添加边距）
        # document = self.document()
        # margin = self.padding
        # painter.translate(margin, margin)
        # document.drawContents(painter)
        # # 恢复状态
        # painter.restore()

class BaseGraphicsItem: # QAbstractGraphicsShapeItem
    def init__(self):
        super().__init__()
        self.text_item = TransparentTextItem(self)
        # 对象属性，包括对象名称、对象转写文本、对象评论
        self.object = ""
        self.transliterate = ""
        self.comment = ""
        self.updatetime = datetime.datetime.now()
        self.comment_datetime = datetime.datetime.now()
    
    def set_attribute(self, label = None, transliterate = None, comment = None,color=None):
        if label is not None:
            self.updatetime = datetime.datetime.now()
            self.object = label
        if transliterate is not None:
            self.updatetime = datetime.datetime.now()
            self.transliterate = transliterate
        if comment is not None:
            self.comment_datetime = datetime.datetime.now()
            self.comment = comment
        attribute_str = self.object
        if self.transliterate != "":
            attribute_str += f": {self.transliterate}"
        if self.comment != "":
            attribute_str += f"  # {self.comment}"
        if color:
            pen = self.pen()
            pen.setColor(color)
            self.setPen(pen)
            # self.text_item.setDefaultTextColor(color)
        self.text_item.setPlainText(attribute_str)
        self.text_item.update()

    def set_pen_size(self, current_scale):
        if self.scene():
            views = self.scene().views()
            if views:
                pen = self.pen()
                base_border_width = views[0].base_border_width
                base_text_size = views[0].base_text_size
                pen.setWidthF(base_border_width / current_scale)
                self.setPen(pen)
                font = self.text_item.font()
                font.setPointSize(max(int(base_text_size // current_scale),1))
                self.text_item.setFont(font)
                self.handle_pen.setWidthF(base_border_width / current_scale)
                self.scene().update(views[0].sceneRect())
    def get_handle_pen_size(self, handle_index = None):
        if self.scene() and handle_index >= 0:
            views = self.scene().views()
            if views and self.active_handle >=0:
                if current_scale is not None:
                    current_scale = views[0].get_current_scale()
                base_border_width = views[0].base_border_width
                self.handle_pen.setWidthF(base_border_width / current_scale)

    
class ResizableGraphicsRectItem(QGraphicsRectItem,BaseGraphicsItem):
    
    handle_cursor = {
        0: Qt.SizeFDiagCursor,
        1: Qt.SizeVerCursor,
        2: Qt.SizeBDiagCursor,
        3: Qt.SizeHorCursor,
        4: Qt.SizeFDiagCursor,
        5: Qt.SizeVerCursor,
        6: Qt.SizeBDiagCursor,
        7: Qt.SizeHorCursor
    }
    # 设定在控制点上的光标形状
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        super().init__()
        self.shape_name = 'rect'
        self.setAcceptHoverEvents(True)  # 设定为接受 hover 事件
        self.setFlags(QGraphicsItem.ItemIsSelectable |  # 设定矩形框为可选择的
                      QGraphicsItem.ItemSendsGeometryChanges |  # 追踪图元改变的信息
                      QGraphicsItem.ItemIsFocusable |  # 可聚焦
                      QGraphicsItem.ItemIsMovable
                      )  # 可移动

        self.handle_size = 8.0
        self.handle_cursor = {
            0: Qt.SizeFDiagCursor, 1: Qt.SizeVerCursor, 2: Qt.SizeBDiagCursor,
            3: Qt.SizeHorCursor, 4: Qt.SizeHorCursor, 5: Qt.SizeBDiagCursor,
            6: Qt.SizeVerCursor, 7: Qt.SizeFDiagCursor
        }
        self.handles = [QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self) for i in range(8)]
        self.active_handle = -1
        self.handle_brush = QBrush(QColor(255, 0, 0, 0))
        self.handle_pen = QPen(Qt.GlobalColor.yellow)
        # self.handle_pen.setWidth(1)
        self.create_handles()
        self.update_text_position()
        self.oldRect = QRectF()
        
    def boundingRect(self):
        """
        限制图元的可视化区域，且防止出现图元移动留下残影的情况
        """
        o = self.text_item.boundingRect().height() - 5
        # 添加一个间隔为 o 的外边框
        return self.rect().adjusted(-o, -o, o, o)

    def create_handles(self):
        for i in range(8):
            self.handles[i] = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self)
            self.handles[i].setBrush(self.handle_brush)
            self.handles[i].setPen(self.handle_pen)
            # self.handles[i].setVisible(False)
            
    def shape(self):
        """创建包含多边形和所有手柄的组合路径"""
        # path = QPainterPath()
        path = super().shape()
        # 2. 添加每个手柄的椭圆路径
        for handle in self.handles:
            handle_center = handle.pos()  # 手柄在父项（多边形）中的位置
            ellipse_rect = QRectF(
                handle_center.x() - self.handle_size/2,
                handle_center.y() - self.handle_size/2,
                self.handle_size,
                self.handle_size
            )
            path.addEllipse(ellipse_rect)
        return path
    
    def update_handles_pos(self):
        rect = self.rect()
        top_left = rect.topLeft()
        top_right = rect.topRight()
        bottom_left = rect.bottomLeft()
        bottom_right = rect.bottomRight()
        center = rect.center()
        
        # for i in range(8):
        #     self.handles[i].setBrush(self.handle_brush)
        #     self.handles[i].setPen(self.handle_pen)
        self.handles[0].setPos(top_left.x() - self.handle_size/2, top_left.y() - self.handle_size/2) # 左上
        self.handles[1].setPos(center.x() - self.handle_size/2, top_left.y() - self.handle_size/2) # 中上
        self.handles[2].setPos(top_right.x() - self.handle_size/2, top_right.y() - self.handle_size/2) # 右上
        self.handles[3].setPos(top_left.x() - self.handle_size/2, center.y() - self.handle_size/2) # 左中
        self.handles[4].setPos(top_right.x() - self.handle_size/2, center.y() - self.handle_size/2) # 右中
        self.handles[5].setPos(top_left.x() - self.handle_size/2, bottom_left.y() - self.handle_size/2) # 左下
        self.handles[6].setPos(center.x() - self.handle_size/2, bottom_left.y() - self.handle_size/2) # 中下
        self.handles[7].setPos(top_right.x() - self.handle_size/2, bottom_right.y() - self.handle_size/2) # 右下
        
    def update_text_position(self):
        rect = self.rect()
        center = rect.center()
        self.text_item.setPos(rect.x(), 
                             rect.top())
        self.text_item.update()
        
    def boundingRect(self):
        # o = self.text_item.boundingRect().height() - 5
        return super().boundingRect().adjusted(-self.handle_size, -self.handle_size, 
                                              self.handle_size, self.handle_size)
    
    def paint(self, painter, option, widget=None):
        if not painter.isActive():
            painter.begin(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        # if self.isSelected():
        self.update_handles_pos()
        # else:
        #     for i in range(8):
        #         self.handles[i].setVisible(False)
        self.update_text_position()
        super().paint(painter, option, widget)
        
    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemSelectedHasChanged:
            self.update()
        elif change == QGraphicsItem.ItemPositionHasChanged or change == QGraphicsItem.ItemTransformHasChanged:
            self.update_text_position()
        return super().itemChange(change, value)
    
    
    def handle_at(self, point):
        """
        返回给定 point 下的控制点 handle
        """
        pad = QMarginsF(self.handle_size,self.handle_size,self.handle_size,self.handle_size)
        for k, v, in enumerate(self.handles):
            pos = v.pos()
            rect = v.rect().adjusted(pos.x(), pos.y(), pos.x(), pos.y())
            if (rect + pad).contains(point) and v.isVisible():
                return k
        return -1
    
    def hoverMoveEvent(self, event):
        """
        当鼠标移到该 item（未按下）上时执行
        """
        super().hoverMoveEvent(event)
        handle = self.handle_at(event.pos())
        if handle == -1:
            cursor = Qt.SizeAllCursor
            self.handle_pen.setWidth(self.handle_size)
            for i in range(8):
                self.handles[i].setBrush(self.handle_brush)
                self.handles[i].setPen(self.handle_pen)
        else:
            cursor = self.handle_cursor[handle]
            handle_pen = self.handles[handle].pen()
            handle_pen.setWidth(self.handle_size*2)
            self.handles[handle].setBrush(self.handle_brush)
            self.handles[handle].setPen(handle_pen)
                    
        self.setCursor(cursor)
        # else:
        #     cursor = Qt.SizeAllCursor
        #     self.setCursor(cursor)

    def hoverLeaveEvent(self, event):
        """
        当鼠标离开该形状（未按下）上时执行。
        """
        super().hoverLeaveEvent(event)
        self.setCursor(Qt.ArrowCursor)  # 设定鼠标光标形状
        self.handle_pen.setWidth(self.handle_size)
        for i in range(8):
            self.handles[i].setBrush(self.handle_brush)
            self.handles[i].setPen(self.handle_pen)

    def mousePressEvent(self, event:QGraphicsSceneMouseEvent):
        self.oldRect = self.rect()
        position = event.scenePos().toPoint()
        self.active_handle = self.handle_at(event.pos())
        if self.active_handle == -1:
            super().mousePressEvent(event)
        else:
            self.setSelected(True)
            
    def mouseMoveEvent(self, event:QGraphicsSceneMouseEvent):
        if self.active_handle >= 0 and self.isSelected():
            item_pos = self.pos()
            parent_pos = self.parentItem().pos()
            rect = self.rect()
            new_rect = rect.adjusted(item_pos.x(), item_pos.y(), item_pos.x(), item_pos.y()) # 消除移动本身pos带来的偏差
            # 消除移动parentItem pos带来的偏差
            pos = event.scenePos().toPoint()  # scene 的pos
            pos.setX(pos.x() - parent_pos.x())
            pos.setY(pos.y() - parent_pos.y())
            if self.active_handle == 0:  # Top-left
                new_rect.setTopLeft(pos)
            elif self.active_handle == 1:  # Top-center
                new_rect.setTop(pos.y())
            elif self.active_handle == 2:  # Top-right
                new_rect.setTopRight(pos)
            elif self.active_handle == 3:  # Middle-left
                new_rect.setLeft(pos.x())
            elif self.active_handle == 4:  # Middle-right
                new_rect.setRight(pos.x())
            elif self.active_handle == 5:  # Bottom-left
                new_rect.setBottomLeft(pos)
            elif self.active_handle == 6:  # Bottom-center
                new_rect.setBottom(pos.y())
            elif self.active_handle == 7:  # Bottom-right
                new_rect.setBottomRight(pos)
            # 限制最小宽度，避免宽度过小
            if new_rect.width() < 10: # 
                if self.active_handle in [0, 3, 5]:
                    new_rect.setLeft(new_rect.right() - 10)
                else:
                    new_rect.setRight(new_rect.left() + 10)
            # 限制最小高度，避免高度过小
            if new_rect.height() < 10:
                if self.active_handle in [0, 1, 2]:
                    new_rect.setTop(new_rect.bottom() - 10)
                else:
                    new_rect.setBottom(new_rect.top() + 10)
            # self.new_rect = new_rect
            self.setRect(new_rect)
            self.setPos(QPointF()) # 移除pos()带来的偏差
            # pointO = self.oldRect.center()
            # pointC = self.rect().center()
            # delta = pointO - pointC
            # if delta != QPointF():
            #     self.scene().views()[0].undo_stack.push(ItemResizeCommand(self, self.oldRect, delta))
            event.accept()
        else:
            super().mouseMoveEvent(event)
            
    def mouseReleaseEvent(self, event:QGraphicsSceneMouseEvent):
        try: 
            
            self.active_handle = -1
            pointO = self.oldRect.center()
            # 移除pos()带来的偏差
            item_pos = self.pos()
            rect = self.rect().adjusted(item_pos.x(), item_pos.y(), item_pos.x(), item_pos.y())
            self.setRect(rect)
            self.setPos(QPointF()) 
            
            pointC = self.rect().center()
            delta = pointO - pointC
            if delta != QPointF():
                self.scene().views()[0].undo_stack.push(ItemResizeCommand(self.scene(),self, self.oldRect, delta))
        except Exception as e:
            traceback.print_exception(e)
        super().mouseReleaseEvent(event)

class ResizableGraphicsPolygonItem(QGraphicsPolygonItem,BaseGraphicsItem):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        super().init__()
        self.shape_name = 'polygon'
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.setAcceptHoverEvents(True)  # 设定为接受 hover 事件
        self.handles = []
        self.handle_size = 8.0
        self.handle_brush = QBrush(QColor(255, 0, 0))
        self.handle_pen = QPen(QColor(0, 0, 0))
        self.handle_pen.setWidth(1)
        self.active_handle = -1
        self.update_text_position()
        self.create_handles()
        self.oldPolygon = QPolygonF()
        self.oldPos = self.pos()
    def create_handles(self):
        for i in range(len(self.polygon())):
            handle = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self)
            handle.setBrush(self.handle_brush)
            handle.setPen(self.handle_pen)
            handle.setVisible(False)
            self.handles.append(handle)
        self.update_handles_pos()
        
    def update_handles_pos(self):
        polygon = self.polygon()
        for i, handle in enumerate(self.handles):
            point = polygon[i]
            handle.setPos(point.x() - self.handle_size/2, point.y() - self.handle_size/2)
            
    def update_text_position(self):
        polygon = self.polygon()
        center = QPointF(0, 0)
        for point in polygon:
            center += point
        center /= len(polygon)
        if polygon.size() > 0:
            pos = polygon.at(0)
            self.text_item.setPos(pos.x(), pos.y())
            
    def boundingRect(self):
        return super().boundingRect().adjusted(-self.handle_size, -self.handle_size, 
                                              self.handle_size, self.handle_size)
    
    def shape(self):
        """创建包含多边形和所有手柄的组合路径"""
        # path = QPainterPath()
        path = super().shape()
        # 2. 添加每个手柄的椭圆路径
        for handle in self.handles:
            handle_center = handle.pos()  # 手柄在父项（多边形）中的位置
            ellipse_rect = QRectF(
                handle_center.x() - self.handle_size/2,
                handle_center.y() - self.handle_size/2,
                self.handle_size,
                self.handle_size
            )
            path.addEllipse(ellipse_rect)
        return path
    
    def paint(self, painter, option, widget=None):
        if not painter.isActive():
            painter.begin(self)
        painter.setRenderHint(QPainter.Antialiasing)
        if self.isSelected():
            for handle in self.handles:
                handle.setVisible(True)
            self.update_handles_pos()
        else:
            for handle in self.handles:
                handle.setVisible(False)
        self.update_text_position()
        super().paint(painter, option, widget)
                
    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemSelectedHasChanged:
            self.update()
        elif change == QGraphicsItem.ItemPositionHasChanged or change == QGraphicsItem.ItemTransformHasChanged:
            self.update_text_position()
            # 多边形即将变化，value 是新的多边形
            new_polygon = value
            # self.scene().views()[0].undo_stack.push(ItemResizeCommand(self, self.oldPolygon, None))
            
        # 继续处理其他变化
        return super().itemChange(change, value)
    
    def handle_at(self, point):
        """
        返回给定 point 下的控制点 handle
        """
        pad = QMarginsF(2,2,2,2)
        for k, v, in enumerate(self.handles):
            pos = v.pos()
            rect = v.rect().adjusted(pos.x(), pos.y(), pos.x(), pos.y())
            if (rect + pad).contains(point) and v.isVisible():
                return k
        return -1

    def hoverMoveEvent(self, event):
        """
        当鼠标移到该 item（未按下）上时执行
        """
        super().hoverMoveEvent(event)
        if self.isSelected():
            handle = self.handle_at(event.pos())
            if handle is None:
                cursor = Qt.SizeAllCursor
            else:
                cursor = Qt.CursorShape.CrossCursor
            self.setCursor(cursor)
        else:
            cursor = Qt.SizeAllCursor
            self.setCursor(cursor)

    def hoverLeaveEvent(self, event):
        """
        当鼠标离开该形状（未按下）上时执行。
        """
        super().hoverLeaveEvent(event)
        self.setCursor(Qt.ArrowCursor)  # 设定鼠标光标形状
        
    def mousePressEvent(self, event:QGraphicsSceneMouseEvent):
        position = event.scenePos().toPoint()
        self.active_handle = self.handle_at(event.pos())
        self.oldPolygon = self.polygon()
        self.oldPos = self.pos()
        if self.active_handle == -1:
            super().mousePressEvent(event)
        else:
            self.setSelected(True)
            
    def mouseMoveEvent(self, event:QGraphicsSceneMouseEvent):
        if self.active_handle >= 0 and self.isSelected():
            polygon = self.polygon()
            
            item_pos = self.pos()
            parent_pos = self.parentItem().pos()
            position = event.scenePos().toPoint()  # scene 的pos
            # 消除移动本身pos带来的偏差
            position.setX(position.x() - item_pos.x())
            position.setY(position.y() - item_pos.y())
            # 消除移动parentItem pos带来的偏差
            position.setX(position.x() - parent_pos.x())
            position.setY(position.y() - parent_pos.y())
            
            polygon[self.active_handle] = position  # 修复弃用警告
            self.setPolygon(polygon)
            self.update_handles_pos()
            event.accept()
        else:
            super().mouseMoveEvent(event)
            
    def mouseReleaseEvent(self, event:QGraphicsSceneMouseEvent):
        self.active_handle = -1
        
        if self.oldPolygon != self.polygon():
            self.scene().views()[0].undo_stack.push(ItemResizeCommand(self.scene(),self, self.oldPolygon, None))
        if self.oldPos != self.pos():
            try:
                self.scene().views()[0].undo_stack.push(ItemMoveCommand(self.scene(),self, self.oldPos))
            except Exception as e:
                info = traceback.format_exc()
                print(info)
        super().mouseReleaseEvent(event)

class ResizableGraphicsQuadrilateralItem(ResizableGraphicsPolygonItem,BaseGraphicsItem):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        super().init__()
        self.shape_name = 'quadrilateral'


class ResizableArrowItem(QGraphicsLineItem,BaseGraphicsItem):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        super().init__()
        self.shape_name = 'arrow'
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.handle_size = 8.0
        self.handle_brush = QBrush(QColor(255, 0, 0))
        self.handle_pen = QPen(QColor(0, 0, 0))
        self.handle_pen.setWidth(1)
        self.head_length = 10.0
        self.head_angle = math.pi / 6
        self.start_handle = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self)
        self.end_handle = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self)
        self.start_handle.setBrush(self.handle_brush)
        self.start_handle.setPen(self.handle_pen)
        self.end_handle.setBrush(self.handle_brush)
        self.end_handle.setPen(self.handle_pen)
        self.start_handle.setVisible(False)
        self.end_handle.setVisible(False)
        self.update_text_position()
        self.active_handle = -1
        
    def update_handles_pos(self):
        line = self.line()
        self.start_handle.setPos(line.p1().x() - self.handle_size/2, line.p1().y() - self.handle_size/2)
        self.end_handle.setPos(line.p2().x() - self.handle_size/2, line.p2().y() - self.handle_size/2)
        
    def update_text_position(self):
        line = self.line()
        center = QPointF((line.p1().x() + line.p2().x()) / 2, (line.p1().y() + line.p2().y()) / 2)
        self.text_item.setPos(center.x() - self.text_item.boundingRect().width()/2, 
                             center.y() - self.text_item.boundingRect().height()/2 - 10)
        
    def boundingRect(self):
        rect = super().boundingRect()
        return rect.adjusted(-self.handle_size, -self.handle_size, self.handle_size, self.handle_size)
    
    def paint(self, painter, option, widget=None):
        if not painter.isActive():
            painter.begin(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        # Draw arrow head
        line = self.line()
        angle = math.atan2(-line.dy(), line.dx())
        
        arrow_p1 = line.p2() - QPointF(
            math.cos(angle - self.head_angle) * self.head_length,
            math.sin(angle - self.head_angle) * self.head_length
        )
        arrow_p2 = line.p2() - QPointF(
            math.cos(angle + self.head_angle) * self.head_length,
            math.sin(angle + self.head_angle) * self.head_length
        )
        
        painter.drawLine(line.p2(), arrow_p1)
        painter.drawLine(line.p2(), arrow_p2)
        
        if self.isSelected():
            self.start_handle.setVisible(True)
            self.end_handle.setVisible(True)
            self.update_handles_pos()
            self.update_text_position()
        else:
            self.start_handle.setVisible(False)
            self.end_handle.setVisible(False)
        super().paint(painter, option, widget)
                
    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemSelectedHasChanged:
            self.update()
        elif change == QGraphicsItem.ItemPositionHasChanged or change == QGraphicsItem.ItemTransformHasChanged:
            self.update_text_position()
        return super().itemChange(change, value)
    
    def mousePressEvent(self, event:QGraphicsSceneMouseEvent):
        position = event.scenePos().toPoint()
        if self.start_handle.isVisible() and self.start_handle.contains(position):  # 修复弃用警告
            self.active_handle = 0
            event.accept()
        elif self.end_handle.isVisible() and self.end_handle.contains(position):  # 修复弃用警告
            self.active_handle = 1
            event.accept()
        else:
            self.active_handle = -1
            super().mousePressEvent(event)
            
    def mouseMoveEvent(self, event:QGraphicsSceneMouseEvent):
        position = event.scenePos().toPoint()
        if self.active_handle == 'start':
            line = self.line()
            self.setLine(QLineF(position, line.p2()))  # 修复弃用警告
            event.accept()
        elif self.active_handle == 'end':
            line = self.line()
            self.setLine(QLineF(line.p1(), position))  # 修复弃用警告
            event.accept()
        else:
            super().mouseMoveEvent(event)
            
    def mouseReleaseEvent(self, event:QGraphicsSceneMouseEvent):
        self.active_handle = None
        super().mouseReleaseEvent(event)


# region item 动作命令
class ItemAddCommand(QUndoCommand):
    def __init__(self, scene, item,image_item):
        super().__init__()
        self.scene = scene
        self.item = item
        self.image_item = image_item
        # self.setText('添加' + self.item.shape_name)
    def undo(self):
        self.setText('删除' + self.item.shape_name)
        self.scene.removeItem(self.item)
        views = self.scene.views()
        if views:
            views[0].updateAnnotationsChanged.emit()
        
    def redo(self):
        self.setText('添加' + self.item.shape_name)
        self.item.setParentItem(self.image_item)
        self.item.updatetime = datetime.datetime.now()
        if self.item not in self.scene.items():
            self.scene.addItem(self.item)
        views = self.scene.views()
        if views:
            current_scale = views[0].get_current_scale()
            views[0].updateAnnotationsChanged.emit()
            self.item.set_pen_size(current_scale)

class ItemMoveCommand(QUndoCommand):
    def __init__(self, scene, item, oldPos):
        super(ItemMoveCommand, self).__init__()
        self.scene = scene
        self.item = item
        self.oldPos = oldPos
        self.newPos = self.item.pos()

    def redo(self):
        self.item.setPos(self.newPos)
        self.setText(self.item.shape_name + '移动 %d %d' % (self.item.pos().x(), self.item.pos().y()))
        self.item.updatetime = datetime.datetime.now()
        views = self.scene.views()
        if views:
            views[0].updateAnnotationsChanged.emit()

    def undo(self):
        self.item.setPos(self.oldPos)
        self.setText(self.item.shape_name + '移动 %d %d' % (self.item.pos().x(), self.item.pos().y()))
        self.item.updatetime = datetime.datetime.now()
        views = self.scene.views()
        if views:
            views[0].updateAnnotationsChanged.emit()

class ItemResizeCommand(QUndoCommand):
    def __init__(self, scene, item, oldRect, delta):
        super(ItemResizeCommand, self).__init__()
        self.scene = scene
        self.item = item
        self.oldRect = oldRect
        self.delta = delta

        if isinstance(self.item, ResizableArrowItem):
            self.s = self.item.active_handle
            if self.item.active_handle == 0:
                self.newPath = self.item.line().p1()
            else:
                self.newPath = self.item.line().p2()
        elif isinstance(self.item, ResizableGraphicsPolygonItem) or isinstance(self.item, ResizableGraphicsQuadrilateralItem):
            Polygon = self.item.polygon()
            self.h = self.item.active_handle
            self.newPolygon = QPolygonF(Polygon)
        elif isinstance(self.item, ResizableGraphicsRectItem):
            self.h = self.item.active_handle
            self.newRect =self.item.rect()
        self.setText(self.item.shape_name + '调整')

    def redo(self):
        if isinstance(self.item, ResizableArrowItem):
            if self.s == 0:
                line = self.item.line()
                line.setP1(self.newPath)
                self.item.setLine(line)
                self.item.update()
                # GraphicView().update()
                self.setText(self.item.shape_name + '调整P1 %d %d' % (self.newPath.x(), self.newPath.y()))
            elif self.s == 1:
                line = self.item.line()
                line.setP2(self.newPath)
                self.item.setLine(line)
                self.item.update()
                # GraphicView().update()
                self.setText(self.item.shape_name + '调整P2 %d %d' % (self.newPath.x(), self.newPath.y()))
        elif isinstance(self.item, ResizableGraphicsRectItem):
            self.item.setRect(self.newRect)
            # self.item.updateCoordinate()
            # self.item.moveBy(-self.delta.x(), -self.delta.y())
            self.setText(self.item.shape_name + '调整(%s) %d %d' % (self.h, self.item.rect().width(), self.item.rect().height()))
        elif isinstance(self.item, ResizableGraphicsPolygonItem) or isinstance(self.item, ResizableGraphicsQuadrilateralItem):
            self.item.setPolygon(self.newPolygon)
            self.setText(self.item.shape_name + '调整(%s) %d %d' % (self.h, self.item.polygon()[self.h -1].x(), self.item.polygon()[self.h -1].y()))
        self.item.update()
        self.item.updatetime = datetime.datetime.now()
        views = self.scene.views()
        if views:
            views[0].updateAnnotationsChanged.emit()

    def undo(self):
        if isinstance(self.item, ResizableArrowItem):
            if self.s == 0:
                line = self.item.line()
                line.setP1(self.oldRect)
                self.item.setLine(line)
                self.item.update()
                # GraphicView().update()
                self.setText(self.item.shashape_namepe + '调整P1 %d %d' % (self.oldRect.x(), self.oldRect.y()))
            elif self.s == 1:
                line = self.item.line()
                line.setP2(self.oldRect)
                self.item.setLine(line)
                self.item.update()
                # GraphicView().update()
                self.setText(self.item.shape_name + '调整P2 %d %d' % (self.oldRect.x(), self.oldRect.y()))
        elif isinstance(self.item, ResizableGraphicsRectItem):
            self.item.setRect(self.oldRect)
            # self.item.updateCoordinate()
            # self.item.moveBy(self.delta.x(), self.delta.y())
            self.setText(self.item.shape_name + '调整(%s) %d %d' % (self.h, self.item.rect().width(), self.item.rect().height()))
        elif isinstance(self.item, ResizableGraphicsPolygonItem) or isinstance(self.item, ResizableGraphicsQuadrilateralItem):
            self.item.setPolygon(self.oldRect)
            self.setText(self.item.shape_name + '调整(%s) %d %d' % (self.h, self.item.polygon()[self.h -1].x(), self.item.polygon()[self.h -1].y()))
        self.item.update()
        self.item.updatetime = datetime.datetime.now()
        views = self.scene.views()
        if views:
            views[0].updateAnnotationsChanged.emit()

class ItemotateCommand(QUndoCommand):
    def __init__(self, item, oldAngle):
        super(ItemotateCommand, self).__init__()
        self.item = item
        self.oldAngle = oldAngle
        self.newAngle = self.item.rotation()

    def redo(self):
        self.item.setRotation(self.newAngle)
        self.setText(self.item.shape_name + '旋转 %d °' % (self.item.rotation()))
        self.item.updatetime = datetime.datetime.now()
        views = self.scene.views()
        if views:
            views[0].updateAnnotationsChanged.emit()

    def undo(self):
        self.item.setRotation(self.oldAngle)
        self.setText(self.item.shape_name + '旋转 %d °' % (self.item.rotation()))
        self.item.updatetime = datetime.datetime.now()
        views = self.scene.views()
        if views:
            views[0].updateAnnotationsChanged.emit()

class ItemDelCommand(QUndoCommand):
    def __init__(self, scene, item,image_item):
        super(ItemDelCommand, self).__init__()
        self.scene = scene
        self.image_item = image_item
        self.item = item
        if isinstance(self.item, ResizableArrowItem):
            self.setText('删除箭头')
        elif isinstance(self.item, ResizableGraphicsRectItem):
            self.setText('删除矩形')
        elif isinstance(self.item, ResizableGraphicsQuadrilateralItem):
            self.setText('删除四边形')
        elif isinstance(self.item, ResizableGraphicsPolygonItem):
            self.setText('删除多边形')
        else:
            self.setText('删除图元')

    def redo(self):
        self.scene.removeItem(self.item)
        self.scene.update()
        views = self.scene.views()
        if views:
            views[0].updateAnnotationsChanged.emit()

    def undo(self):
        self.item.setParentItem(self.image_item)
        if self.item not in self.scene.items():  # 
            self.scene.addItem(self.item)
        views = self.scene.views()
        if views:
            views[0].updateAnnotationsChanged.emit()
            current_scale = views[0].get_current_scale()
            self.item.set_pen_size(current_scale)
        self.scene.update()
        self.item.updatetime = datetime.datetime.now()

# endregion item 动作命令
